﻿using System;
using System.Linq;
using System.Collections.Generic;
using System.Text;
using System.IO;
using System.Runtime.Serialization;
using System.Xml;
using System.Xml.Serialization;
using System.Text.RegularExpressions;
using eeenno.ReaderEngine;
using eeenno.ReaderEngine.Objects;
using eeenno.ReaderEngine.Utilities;

namespace eeenno.ReaderEngine.Adapters
{
    /// <summary>
    /// Caching engine manages all interactions with the Speeed Reader article cache
    /// </summary>
    public class CacheEngine
    {
        private static string _TAGS_FILE_NAME = "tags.eee";
        private static string _STORAGE_CARD = String.Empty;

        public static string storage_card_path
        {
            get
            {
                return _STORAGE_CARD;
            }
        }

        public static bool CopyCache(string source, string dest)
        {
            try
            {
                Directory.Delete(dest, true);
                Directory.Move(source, dest);
            }
            catch (Exception e)
            {
                return false;
            }
            return true;
        }

        /// <summary>
        /// returns value stating if a memory card is loaded on the device
        /// </summary>
        /// <returns></returns>
        public static bool InitializeStorageCardPath()
        {
            DirectoryInfo rootDir = new DirectoryInfo(@"\");
            if (_STORAGE_CARD.Length > 0)
            {
                return true;
            }

            FileAttributes attrStorageCard = FileAttributes.Directory | FileAttributes.Temporary;
            foreach (FileSystemInfo fsi in rootDir.GetFileSystemInfos())
            {
                if ((fsi.Attributes & attrStorageCard) == attrStorageCard)
                {
                    _STORAGE_CARD = fsi.FullName;
                    return true;
                }
            }
            
            return false; 
        }

        public static bool EmptyCache()
        {
            DirectoryInfo info = new DirectoryInfo(Settings.cache_path);
            try
            {
                info.Delete(true); 
                return true;
            }
            catch (Exception e)
            {
                LogManager.LogError("CacheEngine.EmptyCache", e.Message);
                return false;
            }
        }

        public static string[] GetCacheFileList()
        {
            string[] ret_val = null;
            string cache_path = GetCachePath();
            if (cache_path.Length == 0 || !Settings.caching_enabled)
            {
                return ret_val;
            }
            DirectoryInfo info = new DirectoryInfo(cache_path);
            FileInfo[] file_info = info.GetFiles("*.xml");
            ret_val = new string[file_info.Length];
            for (int i = 0; i < file_info.Length; i++)
            {
                ret_val[i] = file_info[i].Name.Replace(".xml",String.Empty);
            }
            return ret_val;
        }

        public static long GetCacheSize()
        {
            long ret_val = 0;
            string cache_path = GetCachePath();
            if (cache_path.Length == 0 || !Settings.caching_enabled)
            {
                return ret_val;
            }
            DirectoryInfo info = new DirectoryInfo(cache_path);
            FileInfo[] file_info = info.GetFiles("*.xml");
            for (int i = 0; i < file_info.Length; i++)
            {
                ret_val += (long)file_info[i].Length;
            }

            return ret_val;
        }

        /// <summary>
        /// Returns a path to the article cache
        /// </summary>
        /// <param name="tagname"></param>
        /// <returns></returns>
        private static string GetCachePath()
        {
            string path = Settings.cache_path + Settings.username + "\\";
            if (!Directory.Exists(path))
            {
                try
                {
                    Directory.CreateDirectory(path);
                }
                catch (Exception e)
                {
                    return String.Empty;
                }
            }
            return path;
        }

        /// <summary>
        /// Returns a path to the article cache
        /// </summary>
        /// <param name="tagname"></param>
        /// <returns></returns>
        private static string GetCachePath(string file_name)
        {
            file_name = Regex.Replace(file_name, @"[\W]", String.Empty);
            return GetCachePath() + file_name + ".xml";                   
        }

        /// <summary>
        /// Imports a subscription from an exported subscription file
        /// </summary>
        /// <param name="sub_name"></param>
        /// <returns></returns>
        public static Subscription ImportSubscription(string item_name)
        {
            Subscription ret_val = null;
            XmlSerializer serializer = null;
            try
            {
                using (TextReader reader = new StreamReader(GetCachePath(item_name)))
                {
                    serializer = new XmlSerializer(typeof(Subscription));
                    ret_val = (Subscription)serializer.Deserialize(reader);
                    serializer = null;
                }
            }
            catch (Exception e)
            {
                LogManager.LogError("CacheEngine.ImportSubscription", e.Message);
            }

            return ret_val;
        }

        public static bool ExportSubscription(Subscription item)
        {
            bool success = false;
            XmlSerializer serializer = null;
            try
            {
                using (TextWriter writer = new StreamWriter(GetCachePath(item.title)))
                {
                    serializer = new XmlSerializer(typeof(Subscription));
                    serializer.Serialize(writer, item);
                    serializer = null;
                    success = true;
                }
            }
            catch (Exception e)
            {
                LogManager.LogError("CacheEngine.ExportSubscription", e.Message);
            }
            return success;
        }

        /// <summary>
        /// Builds skeleton Tags structure for faster loading
        /// </summary>
        /// <returns></returns>
        public static Tags LoadTags()
        {
            Tags ret_val = new Tags();
            try
            {
                using(TextReader reader = new StreamReader(GetCachePath() + _TAGS_FILE_NAME))
                {
                    string temp;
                    while ((temp = reader.ReadLine()) != null)
                    {
                        string[] array = temp.Split('~');
                        Tag new_tag = new Tag();
                        new_tag.name = array[0];
                        array = array[1].Split('`');
                        for (int i = 0; i < array.Length; i++)
                        {
                            if (array[i].Length > 0)
                            {
                                Subscription new_sub = new Subscription();
                                new_sub.title = array[i];
                                new_tag.subscriptions.Add(new_sub);
                            }
                        }
                        ret_val.Add(new_tag);
                    }
                }
            }
            catch (Exception e)
            {
                LogManager.LogError("CacheEngine.LoadTags", e.Message);
            }
            return ret_val;
        }

        public static bool CacheData(ref Tags items)
        {
            try
            {
                using (TextWriter writer = new StreamWriter(GetCachePath() + _TAGS_FILE_NAME, false))
                {
                    for (int i = 0; i < items.Count; i++)
                    {
                        Tag temp_tag = items.Get(i);
                        StringBuilder sb = new StringBuilder(temp_tag.name);
                        sb.Append("~");
                        for (int j = 0; j < temp_tag.subscriptions.Count; j++)
                        {
                            ExportSubscription(temp_tag.subscriptions.Get(j));
                            sb.Append(temp_tag.subscriptions.Get(j).title);
                            sb.Append("`");
                        }
                        writer.WriteLine(sb.ToString());
                    }                    
                }
                return true;
            }
            catch (Exception e)
            {
                LogManager.LogError("CacheEngine.SaveTagsStructure", e.Message);
                return false;
            }
        }

        public static bool DoesCacheExist()
        {
            string[] cache_list = GetCacheFileList();
            //check to see if there are files in the cache, if not do not attempt the build
            if (cache_list == null || cache_list.Length <= 0)
            {
                return false;
            }
            return true;
        }
    }
}
